/*******************************************************************************
GSprite.cpp

	Author:		LiuDingXi
	e-mail:		liudx@gmail.com
	Date time:	2009-08-07

	Copyright (C) 2009
	All rights reserved.
	
*******************************************************************************/
#include "StdAfx.h"
#include "GSprite.h"

#if (_OS_ == _OS_WINNT_)
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#endif//(_OS_ == _OS_WINNT_)

////////////////////////////////////////////////////////////////////////////////

GSprite::GSprite()
{
	m_pSight = NULL;

	m_pBase = NULL;
	m_pThis = NULL;

	m_bVisible = false;

	m_nAction = 0;
	m_nFrame = 0;
	m_nDelay = 0;
	m_nUpdated = 0;
}

GSprite::~GSprite()
{
}

BOOL GSprite::DataBind(GSight* pSight, const BYTE* pBase, SceneDat::PTR ptr)
{
	m_pSight = pSight;

	m_pBase = pBase;
	m_pThis = (const SPRITE*)(pBase + ptr);

	m_nAction = 0;
	m_nFrame = 0;

	return TRUE;
}

bool GSprite::IsVisible()const
{
	if(m_pThis)
	{
		return m_bVisible;
	}
	return false;
}

SINT GSprite::HitTest(int x, int y)
{
	POS refPos;
	if(GetPos(refPos))
	{
		if( x > refPos.x &&
			y > refPos.y &&
			x < refPos.x + refPos.cx &&
			y < refPos.y + refPos.cy )
		{
			return 0;
		}
	}
	return -1;
}

void GSprite::OnDraw(GDC* pDC)
{
	OnDrawFrame(pDC, m_nAction, m_nFrame, m_nPosX, m_nPosY);	
}

void GSprite::OnDraw( GDC* pDC, int x, int y, int frame )
{
	SetPos(x,y);
	SetAction(m_nAction);
	SetActFrame(frame);
	OnDraw(pDC);
}
void GSprite::Update(UINT nMillisecond)
{
	if(m_pThis && m_nAction < m_pThis->nAction && m_nAction >= 0)
	{
		const ACTION* pAction = (const ACTION*)
			(m_pBase + m_pThis->pAction[m_nAction]);

		if(pAction->nFrame > 1 && pAction->nFlags != ACF_STATIC)
		{
			m_nDelay -= nMillisecond;
			if(m_nDelay <= 0)
			{
				m_nFrame++;
				if(m_nFrame >= pAction->nFrame)
				{
					switch(pAction->nFlags)
					{
					case ACF_PLAY_LOOP:
						m_nFrame = 0;
						break;
					case ACF_ANIMATE:
					case ACF_PLAY_ONCE:
						break;
					}
				}
				const FRAME* pFrame = (const FRAME*)
					(m_pBase + pAction->pFrame[m_nFrame]);

				m_nDelay = pFrame->nDelay;
			}
		}
	}
}

SINT GSprite::GetAction()
{
	return m_nAction;
}

SINT GSprite::SetAction(SINT nAction)
{
	SINT nBefore = m_nAction;
	if(m_pThis)
	{
		if(nAction >= 0 && nAction < m_pThis->nAction)
		{
			m_nAction = nAction;
			m_nFrame = 0;

			const ACTION* pAction = (const ACTION*)
				(m_pBase + m_pThis->pAction[m_nAction]);

			const FRAME* pFrame = (const FRAME*)
				(m_pBase + pAction->pFrame[m_nFrame]);

			m_nDelay = pFrame->nDelay;
		}
	}
	return nBefore;
}

SINT GSprite::GetActFrame()const
{
	return m_nFrame;
}

void GSprite::SetActFrame(int nIndex)
{
	if(m_pThis && m_nAction < m_pThis->nAction && m_nAction >= 0)
	{
		const ACTION* pAction = (const ACTION*)
			(m_pBase + m_pThis->pAction[m_nAction]);

		if(nIndex >= 0 && nIndex < pAction->nFrame)
		{
			m_nFrame = nIndex;

			const FRAME* pFrame = (const FRAME*)
				(m_pBase + pAction->pFrame[m_nFrame]);

			m_nDelay = pFrame->nDelay;
		}
	}
}

void GSprite::ResetDelay()
{
	if(m_pThis && m_nAction < m_pThis->nAction && m_nAction >= 0)
	{
		const ACTION* pAction = (const ACTION*)
			(m_pBase + m_pThis->pAction[m_nAction]);

		if(m_nFrame >=0 && m_nFrame < pAction->nFrame)
		{
			const FRAME* pFrame = (const FRAME*)
				(m_pBase + pAction->pFrame[m_nFrame]);

			m_nDelay = pFrame->nDelay;
		}
	}
}

void GSprite::ResetAction()
{
	if(m_pThis && m_nAction < m_pThis->nAction && m_nAction >= 0)
	{
		m_nFrame = 0;
	}
}


BOOL GSprite::IsPlayEnded()const
{
	if(m_nFrame > 0)
	{
		const ACTION* pAction = (const ACTION*)
			(m_pBase + m_pThis->pAction[m_nAction]);

		if(pAction->nFlags != ACF_STATIC)
		{
			if(m_nFrame >= pAction->nFrame)
			{
				return TRUE;
			}
		}
	}
	return FALSE;
}


void GSprite::OnDrawFrame(GDC* pDC, SINT nAction, SINT nFrame, int x, int y)
{
	ASSERT(m_pThis);

	if(nAction < 0 || nAction > m_pThis->nAction)
	{
		nAction = 0;
	}
	const ACTION* pAction = (const ACTION*)
		(m_pBase + m_pThis->pAction[nAction]);

	if(nFrame < 0 || nFrame >= pAction->nFrame)
	{
		switch(pAction->nFlags)
		{
		case ACF_PLAY_ONCE:
			return;
		case ACF_ANIMATE:
			nFrame = pAction->nFrame - 1;
			break;
		case ACF_PLAY_LOOP:
		default:
			nFrame = 0;
			break;
		}
	}

	const FRAME* pFrame = (const FRAME*)(m_pBase + pAction->pFrame[nFrame]);

	for(int i=0; i<pFrame->nFclip; i++)
	{
		const FCLIP* pFclip = (const FCLIP*)(m_pBase + pFrame->pFclip[i]);

		const IMG* pImg = (const IMG*)(m_pBase + pFclip->pImage);

		int w = pFclip->nOffX > 0 ? pFclip->nOffX : pImg->cx;
		int h = pFclip->nOffY > 0 ? pFclip->nOffY : pImg->cy;

		int nPosX = x + pFclip->nPosX;
		int nPosY = y + pFclip->nPosY;

		if(pImg->nType == eImage)
		{
			for(int rx=0; rx<pFclip->nXRep; rx++)
			{
				for(int ry=0; ry<pFclip->nYRep; ry++)
				{
					GCLIP Clip;
					Clip.x = pImg->x;
					Clip.y = pImg->y;
					Clip.cx = pImg->cx;
					Clip.cy = pImg->cy;

					GOPER Oper;
					Oper.fAlpha = pFclip->fAlpha;
					Oper.fAngle = pFclip->fAngle;

					const GImage* pImage = m_pSight->GetImage(pImg->nIdx);
					pDC->Draw(*pImage, nPosX, nPosY + ry*h, Clip, Oper);
				}
				nPosX += w;
			}
		}
		else
		{
			if(m_pSight)
			{
				const STYLE* pStyle = m_pSight->GetStyle(pImg->nIdx);

				switch(pImg->nType)
				{
				case ePoint:
					{

					}
					break;
				case eLine:
					{
						GPoint pt1, pt2;
						pt1.x = nPosX + pImg->x;
						pt1.y = nPosY + pImg->y;
						pt2.x = nPosX + pImg->x2;
						pt2.y = nPosY + pImg->y2;

						pDC->DrawLine(pt1, pt2);
					}
					break;
				case eRect:
					{
						GRect rect;
						rect.x = nPosX + pImg->x;
						rect.y = nPosY + pImg->y;
						rect.cx = pImg->cx;
						rect.cy = pImg->cy;
						pDC->DrawRect(rect);
					}
					break;
				case eRbox:
					break;
				}

			}
		}
	}	
}


CXY GSprite::DrawClip(GDC* pDC, int x, int y, SINT nClip)
{
	ASSERT(m_pThis);

	SINT nAction = m_nAction;
	SINT nFrame = m_nFrame;

	if(nAction < 0 || nAction > m_pThis->nAction)
	{
		nAction = 0;
	}
	const ACTION* pAction = (const ACTION*)
		(m_pBase + m_pThis->pAction[nAction]);

	if(nFrame < 0 || nFrame >= pAction->nFrame)
	{
		nFrame = 0;
	}

	const FRAME* pFrame = (const FRAME*)(m_pBase + pAction->pFrame[nFrame]);

	if(nClip < 0 || nClip >= pFrame->nFclip)
	{
		nClip = 0;
	}

	const FCLIP* pFclip = (const FCLIP*)(m_pBase + pFrame->pFclip[nClip]);
	const IMG* pImg = (const IMG*)(m_pBase + pFclip->pImage);

	GCLIP Clip;
	Clip.x = pImg->x;
	Clip.y = pImg->y;
	Clip.cx = pImg->cx;
	Clip.cy = pImg->cy;

	GOPER Oper;
	Oper.fAlpha = pFclip->fAlpha;
	Oper.fAngle = pFclip->fAngle;

	const GImage* pImage = m_pSight->GetImage(pImg->nIdx);
	pDC->Draw(*pImage, x, y, Clip, Oper);

	CXY cxy;
	cxy.cx = pImg->cx;
	cxy.cy = pImg->cy;
	return cxy;

}

BOOL GSprite::GetCxy(CXY& refCxy)const
{
	if(m_pThis)
	{
		SINT nAction = m_nAction;
		SINT nFrame = m_nFrame;
		if(nAction < 0 || nAction > m_pThis->nAction)
		{
			nAction = 0;
		}
		const ACTION* pAction = (const ACTION*)
			(m_pBase + m_pThis->pAction[nAction]);

		refCxy.cx = 0;
		refCxy.cy = 0;

		if(nFrame < 0 || nFrame >= pAction->nFrame)
		{
			if(pAction->nFlags == ACF_PLAY_ONCE)
				return TRUE;

			nFrame = 0;
		}

		const FRAME* pFrame = (const FRAME*)(m_pBase + pAction->pFrame[nFrame]);

		for(int i=0; i<pFrame->nFclip; i++)
		{
			const FCLIP* pFclip = (const FCLIP*)(m_pBase + pFrame->pFclip[i]);

			const IMG* pImg = (const IMG*)(m_pBase + pFclip->pImage);

			int w = pFclip->nOffX > 0 ? pFclip->nOffX : pImg->cx;
			int h = pFclip->nOffY > 0 ? pFclip->nOffY : pImg->cy;

			int cx = pFclip->nPosX + pFclip->nXRep * w;
			int cy = pFclip->nPosY + pFclip->nYRep * h;

			if(cx > refCxy.cx)
				refCxy.cx = cx;
			if(cy > refCxy.cy)
				refCxy.cy = cy;
		}
		return TRUE;
	}
	return FALSE;
}

BOOL GSprite::GetPos(POS& refPos)const
{
	CXY refCxy;
	if(GetCxy(refCxy))
	{
		refPos.x = m_nPosX;
		refPos.y = m_nPosY;
		refPos.cx = refCxy.cx;
		refPos.cy = refCxy.cy;

		return TRUE;
	}
	return FALSE;
}

void GSprite::SetPosEx(int x, int y, int nFlag)
{
	POS self;
	if(GetPos(self))
	{
		switch(nFlag)
		{
		case PF_TOPLEFT:
			m_nPosX = x;
			m_nPosY = y;
			break;
		case PF_TOPMIDDLE:
			m_nPosX = x - self.cx/2;
			m_nPosY = y;
			break;
		case PF_TOPRIGHT:
			m_nPosX = x - self.cx;
			m_nPosY = y;
			break;
		case PF_LEFTMIDDLE:
			m_nPosX = x;
			m_nPosY = y - self.cy/2;
			break;
		case PF_RIGHTMIDDLE:
			m_nPosX = x - self.cx;
			m_nPosY = y - self.cy/2;
			break;
		case PF_MIDDLE:
			m_nPosX = x - self.cx/2;
			m_nPosY = y - self.cy/2;
			break;
		case PF_BOTTOMLEFT:
			m_nPosX = x;
			m_nPosY = y - self.cy;
			break;
		case PF_BOTTOMRIGHT:
			m_nPosX = x - self.cx;
			m_nPosY = y - self.cy;
			break;
		case PF_BOTTOMMIDDLE:
			m_nPosX = x - self.cx/2;
			m_nPosY = y - self.cy;
			break;
		default:
			m_nPosX = x;
			m_nPosY = y;
			break;
		}
	}
}

BOOL GSprite::GetBox(BOX& refBox)const
{
	CXY refCxy;
	if(GetCxy(refCxy))
	{
		refBox.left = m_nPosX;
		refBox.top = m_nPosY;
		refBox.right = refBox.left + refCxy.cx;
		refBox.bottom = refBox.top + refCxy.cy;

		return TRUE;
	}
	return FALSE;
}
